package org.example.mone.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import org.apache.ibatis.executor.BatchResult;
import org.example.dto.TaskIds;
import org.example.dto.TaskStatus;
import org.example.enums.*;
import org.example.mone.mapper.DeployinfoMapper;
import org.example.mone.mapper.SubtaskMapper;
import org.example.mone.mapper.TaskMapper;
import org.example.mone.model.Deployinfo;
import org.example.mone.model.Subtask;
import org.example.mone.model.Task;
import org.example.mone.task.DeployJob;
import org.example.mone.service.IDeployService;
import org.example.mone.task.UninstallJob;
import org.example.task.ITask;
import org.example.util.ThreadUtil;
import org.example.vo.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;

@Service
public class DeployServiceImpl implements IDeployService {

    private static final Logger LOGGER = LoggerFactory.getLogger(DeployServiceImpl.class);

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DeployinfoMapper deployinfoMapper;

    @Autowired
    private TaskMapper taskMapper;

    @Autowired
    private SubtaskMapper subtaskMapper;


    @Override
    public Result<String> deploy() {
        Result<String> result = Result.ok("deploy success.");
        try {
            Result<TaskIds> rs = deployTaskInit("1");
            ThreadUtil.submitTask(new DeployJob(EDeployTaskStep.CHECKHEALTH,rs.getResult().getTaskId()));
            updateTask(rs.getResult());
        } catch (Exception e) {
            result = Result.error(-1, "deployTaskInit error");
            LOGGER.error("deployTaskInit error", e);
        }
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateTask(TaskIds taskIds){
        Subtask subtask = new Subtask();
        subtask.setStepNum(EDeployTaskStep.CHECKHEALTH.getStepNum());
        subtask.setTaskId(taskIds.getTaskId());
        subtask.setState(ETaskStatus.RUNNING.getCode());
        subtask.setStartTime(DateUtil.date());
        subtaskMapper.updateSubtaskByStepNum(subtask);
        Task task = new Task();
        task.setState(ETaskStatus.RUNNING.getCode());
        task.setId(taskIds.getTaskId());
        task.setStartTime(DateUtil.date());
        taskMapper.updateById(task);
    }


    @Override
    public Result<String> uninstall() {
        ThreadUtil.submitTask(new UninstallJob(EUninstallStep.CHECKHEALTH));
        return Result.ok("deploy success.");
    }

    @Override
    public void stateHandler(String taskStatusStr) {
        Result<TaskStatus> result = JSON.parseObject(taskStatusStr, new TypeReference<Result<TaskStatus>>() {
        });
        TaskStatus taskStatus = result.getResult();
        EJobType jobType = taskStatus.getJobType();
        switch (jobType) {
            case DEPLOY:
                EDeployTaskStep eDeployTaskStep = EDeployTaskStep.getByStepNum(taskStatus.getTaskStep());
                if(result.isSuccess()){
                    ThreadUtil.submitTask(new DeployJob(eDeployTaskStep.getNextStepNum(),taskStatus.getJobId()));
                }
                updateTaskStatus(result.isSuccess(),taskStatus,eDeployTaskStep.getStepNum(),eDeployTaskStep.getNextStepNum().getStepNum(),eDeployTaskStep.getProcess());
                break;
            case UNINSTALL:
                EUninstallStep eUninstallStep = EUninstallStep.getByStepNum(taskStatus.getTaskStep());
                if(result.isSuccess()) {
                    ThreadUtil.submitTask(new UninstallJob(eUninstallStep.getNextStepNum()));
                }
                updateTaskStatus(result.isSuccess(),taskStatus,eUninstallStep.getStepNum(),eUninstallStep.getNextStepNum().getStepNum(),eUninstallStep.getProcess());
                break;
            default:
                throw new RuntimeException("jobType error.");
        }

//        LOGGER.info("stateHandler ...{}, toDB", taskStatus);
    }


    @Transactional(rollbackFor = Exception.class)
    public void updateTaskStatus(boolean flag,TaskStatus taskStatus,int currentStepNum,int nextStepNum,int process) {
        //更新当前subtask状态
        Subtask curSubtask = new Subtask();
        curSubtask.setTaskId(taskStatus.getJobId());
        curSubtask.setStepNum(currentStepNum);
        curSubtask.setEndTime(DateUtil.date());
        Task task = new Task();
        task.setId(taskStatus.getJobId());
        if(flag){
            curSubtask.setState(ETaskStatus.SUCCESS.getCode());
            //更新下一个subtask状态
            Subtask nextSubtask = new Subtask();
            nextSubtask.setTaskId(taskStatus.getJobId());
            nextSubtask.setStepNum(nextStepNum);
            nextSubtask.setStartTime(DateUtil.date());
            nextSubtask.setState(ETaskStatus.RUNNING.getCode());
            subtaskMapper.updateSubtaskByStepNum(nextSubtask);
            if(curSubtask.getStepNum() == EDeployTaskStep.END.getLastStepNum().getStepNum()){
                task.setEndTime(DateUtil.date());
                task.setState(ETaskStatus.SUCCESS.getCode());
            }
        }else {
            curSubtask.setState(ETaskStatus.FAIL.getCode());
            task.setEndTime(DateUtil.date());
            task.setState(ETaskStatus.FAIL.getCode());
        }
        task.setTaskProgress(process);
        subtaskMapper.updateSubtaskByStepNum(curSubtask);
        taskMapper.updateById(task);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<TaskIds> deployTaskInit(String deployId) throws Exception{
        Result<TaskIds> result = Result.ok();
        Deployinfo deployinfo = deployinfoMapper.selectById(deployId);
        long hostId = 1L;
        Task task = new Task();
        task.setTaskName("部署");
        task.setDeployId(Long.parseLong(deployId));
        task.setTaskType(EJobType.DEPLOY.getJobType());
        task.setState(ETaskStatus.INIT.getCode());
        task.setStartTime(DateUtil.date());
        int id = taskMapper.insert(task);
        List<Subtask> list = getSubtaskList(task, hostId);
        subtaskMapper.insert(list);
        LOGGER.info("deployTaskInit jobId={},taskId={}",task.getId(),list.get(0).getId());
        result.setResult(new TaskIds(task.getId(),list.get(0).getId()));
        return result;
    }

    private List<Subtask> getSubtaskList(Task task, long hostId) {
        List<Subtask> list = new ArrayList<>();
        Subtask subtask1 = new Subtask();
        subtask1.setTaskId(task.getId());
        subtask1.setTaskLevel(1);
        subtask1.setHostId(hostId);
        subtask1.setName(EDeployTaskStep.CHECKHEALTH.getCnName());
        subtask1.setState(ETaskStatus.INIT.getCode());
        subtask1.setStepNum(EDeployTaskStep.CHECKHEALTH.getStepNum());
        subtask1.setStepNumName(EDeployTaskStep.CHECKHEALTH.getName());
        subtask1.setCreateTime(DateUtil.date());

        Subtask subtask2 = new Subtask();
        subtask2.setTaskId(task.getId());
        subtask2.setTaskLevel(1);
        subtask2.setHostId(hostId);
        subtask2.setName(EDeployTaskStep.DISKCHECK.getCnName());
        subtask2.setState(ETaskStatus.INIT.getCode());
        subtask2.setStepNum(EDeployTaskStep.DISKCHECK.getStepNum());
        subtask2.setStepNumName(EDeployTaskStep.DISKCHECK.getName());
        subtask2.setCreateTime(DateUtil.date());

        Subtask subtask3 = new Subtask();
        subtask3.setTaskId(task.getId());
        subtask3.setTaskLevel(2);
        subtask3.setHostId(hostId);
        subtask3.setName(EDeployTaskStep.COPY.getCnName());
        subtask3.setState(ETaskStatus.INIT.getCode());
        subtask3.setStepNum(EDeployTaskStep.COPY.getStepNum());
        subtask3.setStepNumName(EDeployTaskStep.COPY.getName());
        subtask3.setCreateTime(DateUtil.date());

        Subtask subtask4 = new Subtask();
        subtask4.setTaskId(task.getId());
        subtask4.setTaskLevel(2);
        subtask4.setHostId(hostId);
        subtask4.setName(EDeployTaskStep.UNZIP.getCnName());
        subtask4.setState(ETaskStatus.INIT.getCode());
        subtask4.setStepNum(EDeployTaskStep.UNZIP.getStepNum());
        subtask4.setStepNumName(EDeployTaskStep.UNZIP.getName());
        subtask4.setCreateTime(DateUtil.date());

        Subtask subtask5 = new Subtask();
        subtask5.setTaskId(task.getId());
        subtask5.setTaskLevel(2);
        subtask5.setHostId(hostId);
        subtask5.setName(EDeployTaskStep.ENVCONFIG.getCnName());
        subtask5.setState(ETaskStatus.INIT.getCode());
        subtask5.setStepNum(EDeployTaskStep.ENVCONFIG.getStepNum());
        subtask5.setStepNumName(EDeployTaskStep.ENVCONFIG.getName());
        subtask5.setCreateTime(DateUtil.date());

        Subtask subtask6 = new Subtask();
        subtask6.setTaskId(task.getId());
        subtask6.setTaskLevel(2);
        subtask6.setHostId(hostId);
        subtask6.setName(EDeployTaskStep.FILECONFIG.getCnName());
        subtask6.setState(ETaskStatus.INIT.getCode());
        subtask6.setStepNum(EDeployTaskStep.FILECONFIG.getStepNum());
        subtask6.setStepNumName(EDeployTaskStep.FILECONFIG.getName());
        subtask6.setCreateTime(DateUtil.date());

        list.add(subtask1);
        list.add(subtask2);
        list.add(subtask3);
        list.add(subtask4);
        list.add(subtask5);
        list.add(subtask6);
        return list;
    }

}
